package com.freewater.cargotracker.infrastructure.persistence.mybatis.mapper;

import com.freewater.cargotracker.infrastructure.persistence.mybatis.dbobject.CarrierMovementPO;
import com.freewater.cargotracker.infrastructure.persistence.mybatis.dbobject.LocationPO;
import com.freewater.cargotracker.infrastructure.persistence.mybatis.dbobject.VoyagePO;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Repository
public class VoyageHelperMapper {

    private final CarrierMovementMapper carrierMovementMapper;
    private final LocationMapper locationMapper;

    public VoyageHelperMapper(CarrierMovementMapper carrierMovementMapper,
                              LocationMapper locationMapper) {
        this.carrierMovementMapper = carrierMovementMapper;
        this.locationMapper = locationMapper;
    }

    public void findVoyageInfo(VoyagePO voyagePO) {
        final Long id = voyagePO.getId();
        final List<CarrierMovementPO> carrierMovementPOs = this.carrierMovementMapper.findByVoyageId(id);
        voyagePO.setCarrierMovements(carrierMovementPOs);
        final List<LocationPO> locationPOs = new ArrayList<>();
        carrierMovementPOs.forEach(po -> {
            locationPOs.add(po.getDepartureLocation());
            locationPOs.add(po.getArrivalLocation());
        });
        //
        final Set<Long> locationIds = extractLocationId(locationPOs);
        //
        List<LocationPO> locationPOS = new ArrayList<>();
        if (!locationIds.isEmpty()) {
            locationPOS = locationMapper.findByIds(locationIds);
        }
        final Map<Long, LocationPO> locationMap = locationPOS.stream().collect(Collectors.toMap(s -> s.getId(), s -> s));
        carrierMovementPOs.forEach(po -> {
            fillLocationPO(po::getDepartureLocation, po::setDepartureLocation, locationMap);
            fillLocationPO(po::getArrivalLocation, po::setArrivalLocation, locationMap);
        });
    }

    private Set<Long> extractLocationId(List<LocationPO> locationPOs) {
        return locationPOs.stream()
                .filter(s -> s != null).map(s -> s.getId()).collect(Collectors.toSet());
    }

    private void fillLocationPO(Supplier<LocationPO> locationIdSupplier,
                                Consumer<LocationPO> consumer,
                                Map<Long, LocationPO> locationPOMap) {
        final LocationPO po = locationIdSupplier.get();
        if (po == null) {
            return;
        }
        final Long locationId = po.getId();
        final LocationPO locationPO = locationPOMap.get(locationId);
        consumer.accept(locationPO);
    }
}
